由于 Flux Images Generation API 生成的時(shí)間相對(duì)較長(zhǎng),大約需要 1-2 分鐘,如果 API 長(zhǎng)時(shí)間無(wú)響應(yīng),HTTP 請(qǐng)求會(huì)一直保持連接,導(dǎo)致額外的系統(tǒng)資源消耗,所以本 API 也提供了異步回調(diào)的支持。
整體流程是:客戶端發(fā)起請(qǐng)求的時(shí)候,額外指定一個(gè) callback_url 字段,客戶端發(fā)起 API 請(qǐng)求之后,API 會(huì)立馬返回一個(gè)結(jié)果,包含一個(gè) task_id 的字段信息,代表當(dāng)前的任務(wù) ID。當(dāng)任務(wù)完成之后,生成圖片的結(jié)果會(huì)通過(guò) POST JSON 的形式發(fā)送到客戶端指定的 callback_url,其中也包括了 task_id 字段,這樣任務(wù)結(jié)果就可以通過(guò) ID 關(guān)聯(lián)起來(lái)了。
{ "success": true, "task_id": "f45388a9-4169-41d4-aec8-fb8259c48d36", "trace_id": "1df9f664-fd74-476b-8038-b0b5f62ddf87", "data": [ { "id": "02702b40-272d-4838-8644-675105930658", "title": "Vibe", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/e850008a-d9a1-4c8f-acbd-a37f228946bc/image/02702b40-272d-4838-8644-675105930658.jpg", "lyric": "[Intro]\nYeah, yeah\nKeep talking, keep talking\nI love the way you sound\n[Verse 1]\nYour voice is like a drug I can't put down\nEvery word you say just pulls me in\nI'm addicted to the way you laugh out loud\nAnd how you whisper when the room goes dim\nTell me 'bout your day, tell me 'bout your fears\nI could listen to you talk for years\n[Pre-Chorus]\nDon't stop now, don't you dare\nI need your voice filling up the air\n[Chorus]\nKeep talking, keep talking to me\nYour words are all I fucking need\nKeep talking, keep talking, I'm high\nOff every sound you make tonight\nKeep talking\n[Verse 2]\nYou could read the phone book, I don't care\nJust the rhythm of your breathing's enough\nWhen you say my name, it's like a prayer\nAnd your silence hits me twice as rough\nEvery conversation feels like home\nNever want to hear this dial tone\n[Pre-Chorus]\nDon't stop now, don't you dare\nI need your voice filling up the air\n[Chorus]\nKeep talking, keep talking to me\nYour words are all I fucking need\nKeep talking, keep talking, I'm high\nOff every sound you make tonight\nKeep talking\n[Bridge]\nWhen the world gets loud and crazy\nYour voice cuts through the noise\nYou're my favorite conversation\nYou're my drug of choice\nKeep talking, keep talking\nKeep talking, keep talking\nKeep talking, keep talking\nKeep talking, keep talking\n[Chorus]\nKeep talking, keep talking to me\nYour words are all I fucking need\nKeep talking, keep talking, I'm high\nOff every sound you make tonight\nKeep talking\n[Outro]\nYeah, yeah\nKeep talking, keep talking\nNever stop that sound", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/e850008a-d9a1-4c8f-acbd-a37f228946bc/audio/02702b40-272d-4838-8644-675105930658.m4a", "video_url": null, "created_at": "2025-06-18T15:47:54.705246Z", "model": "FUZZ-1.0", "lyrics_timestamped": { "words": [ { "text": "[Intro]", "start": 0.64, "end": 0.64, "line_index": 0, "index_range": null, "wav2vec2_format": null }, ... { "text": "sound", "start": 179.84, "end": 180.48, "line_index": 63, "index_range": null, "wav2vec2_format": null } ] }, "state": "succeeded", "style": "Pop, upbeat tempo, modern production", "duration": 181.12 }, { "id": "be3fe757-621e-4017-9056-20aa7f01919e", "title": "Revive", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/e850008a-d9a1-4c8f-acbd-a37f228946bc/image/be3fe757-621e-4017-9056-20aa7f01919e.jpg", "lyric": "[Verse 1]\nI'm walking through the motions, moving day by day\nColors seem a little faded, nothing much to say\nFriends keep calling, asking if I'm doing fine\nBut I just smile and tell them everything's divine\n[Pre-Chorus]\nSomething's missing, can't quite name it\nFeels like I'm just going through the stages\n[Chorus]\nI'm barely breathing, barely feeling\nLike I'm floating through a life that isn't mine\nBarely breathing, barely healing\nSearching for a reason, searching for a sign\nTo feel alive again\nTo feel alive again\n[Verse 2]\nMorning coffee tastes like water, sunrise looks like rain\nEveryone around me laughs but I can't feel the same\nUsed to dance in silly moments, used to sing out loud\nNow I'm standing in the silence of a faceless crowd\n[Pre-Chorus]\nSomething's shifting, can't ignore it\nMaybe it's time to break these patterns\n[Chorus]\nI'm barely breathing, barely feeling\nLike I'm floating through a life that isn't mine\nBarely breathing, barely healing\nSearching for a reason, searching for a sign\nTo feel alive again\nTo feel alive again\n[Bridge]\nBut there's a beating in my chest\nA whisper saying \"don't give up yet\"\nMaybe tomorrow I'll remember\nHow to laugh and how to let\nMy heart wake up from this long sleep\nFind the fire I used to keep\n[Chorus]\nI'm barely breathing, barely feeling\nLike I'm floating through a life that isn't mine\nBarely breathing, barely healing\nSearching for a reason, searching for a sign\nTo feel alive again\nTo feel alive again\n[Outro]\nI'm gonna feel alive again\nI'm gonna feel alive again", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/e850008a-d9a1-4c8f-acbd-a37f228946bc/audio/be3fe757-621e-4017-9056-20aa7f01919e.m4a", "video_url": null, "created_at": "2025-06-18T15:48:01.139081Z", "model": "FUZZ-1.0", "lyrics_timestamped": { "words": [ { "text": "[Verse", "start": 0.64, "end": 0.64, "line_index": 0, "index_range": null, "wav2vec2_format": null }, ... { "text": "again", "start": 202.88, "end": 211.84, "line_index": 54, "index_range": null, "wav2vec2_format": null } ] }, "state": "succeeded", "style": "Pop, upbeat tempo, clean production, emotional vocals", "duration": 211.84 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "FUZZ-1.0", "action": "generate", "prompt": "A song for Christmas" }'
自定義生成
如果想自定義生成歌詞,可以輸入歌詞:
這時(shí)候 lyric 字段可以傳入類似如下內(nèi)容:
1
[Verse]Woke up withthe sun inmy eyesNo clouds above just blue inthe skiesShoes onmy feet I’m ready to runEvery step feels like a loaded gun[Chorus]Happy days are rolling inLet the joy beneathmy skinNo more shadows no more liesJust the truth that lifts me high[Verse 2]Dancing throughthe city streetsA rhythm pounding inmy heartbeatStrangers smile it’s catching onThis world’s a stage we’re all a song[Chorus]Happy days are rolling inLet the joy beneathmy skinNo more shadows no more liesJust the truth that lifts me high[Bridge]Throw your worries out the doorLet them sink tothe ocean floorWe’re alive andit’s enoughLife is messy butit’s love[Chorus]Happy days are rolling inLet the joy beneathmy skinNo more shadows no more liesJust the truth that lifts me high
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "FUZZ-1.0", "action": "generate", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "custom": true }'
{ "success": true, "task_id": "978c2912-6a90-4048-b4c1-43f9cf18c28d", "trace_id": "08dfbb99-43ce-4f65-8fd1-74b98f2b121a", "data": [ { "id": "eac9ab69-e210-490b-9f8d-095a6f074f40", "title": "VibeRise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3f3e1354-52ad-4f5b-902c-5f83abd17def/image/eac9ab69-e210-490b-9f8d-095a6f074f40.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3f3e1354-52ad-4f5b-902c-5f83abd17def/audio/eac9ab69-e210-490b-9f8d-095a6f074f40.m4a", "video_url": null, "created_at": "2025-06-23T01:57:33.438644Z", "model": "FUZZ-1.0", "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, { "end": 0.64, "index_range": null, "line_index": 1, "start": 0.64, "text": "Woke", "wav2vec2_format": null }, ... ] }, "state": "succeeded", "style": "funk vibes, raspy, raw vocal texture", "duration": 158.08 }, { "id": "64fffe1f-b1aa-46dc-8012-b80ba319cf35", "title": "Pure Dawn", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3f3e1354-52ad-4f5b-902c-5f83abd17def/image/64fffe1f-b1aa-46dc-8012-b80ba319cf35.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3f3e1354-52ad-4f5b-902c-5f83abd17def/audio/64fffe1f-b1aa-46dc-8012-b80ba319cf35.m4a", "video_url": null, "created_at": "2025-06-23T01:57:33.963497Z", "model": "FUZZ-1.0", "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, { "end": 0.64, "index_range": null, "line_index": 1, "start": 0.64, "text": "Woke", "wav2vec2_format": null }, ... ] }, "state": "succeeded", "style": "contemporary country", "duration": 175.36 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "action": "cover", "model": "FUZZ-1.0 Pro", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_id": "b7376272-3902-49b4-a83b-62f7e6ab505c" }'
{ "success": true, "task_id": "fe02997d-f58e-4886-9aa3-4074c9a430eb", "trace_id": "997bde4c-6063-4fc2-9b03-d837f1efc72d", "data": [ { "id": "be254182-d4b7-42b3-9ee2-b86db086cff1", "title": "Sunny Rise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/c2f707a9-017d-4354-8bfa-436266dadbf6/image/be254182-d4b7-42b3-9ee2-b86db086cff1.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/c2f707a9-017d-4354-8bfa-436266dadbf6/audio/be254182-d4b7-42b3-9ee2-b86db086cff1.m4a", "video_url": null, "created_at": "2025-06-23T01:59:17.666629Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 237.44, "index_range": null, "line_index": 29, "start": 236.8, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 239.46235827664398 }, { "id": "9b9d2810-eb2b-44d3-85c0-cb259afa13c3", "title": "Uplift", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/c2f707a9-017d-4354-8bfa-436266dadbf6/image/9b9d2810-eb2b-44d3-85c0-cb259afa13c3.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/c2f707a9-017d-4354-8bfa-436266dadbf6/audio/9b9d2810-eb2b-44d3-85c0-cb259afa13c3.m4a", "video_url": null, "created_at": "2025-06-23T01:59:23.065712Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, ... }, { "end": 236.16, "index_range": null, "line_index": 29, "start": 225.28, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 239.5299546485261 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "action": "extend", "model": "FUZZ-1.0 Pro", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_id": "b7376272-3902-49b4-a83b-62f7e6ab505c", "continue_at": 5 }'
{ "success": true, "task_id": "6388a0aa-b5ab-4485-baad-f0e0b7a7848c", "trace_id": "da143dbe-8263-45ac-b05a-1ed57dd4aa79", "data": [ { "id": "209e27e0-500c-44f3-9134-280690014920", "title": "City Rhythm", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3a8378d5-94d4-49b7-9c0a-8432c0c4a39d/image/209e27e0-500c-44f3-9134-280690014920.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3a8378d5-94d4-49b7-9c0a-8432c0c4a39d/audio/209e27e0-500c-44f3-9134-280690014920.m4a", "video_url": null, "created_at": "2025-06-23T02:00:53.473604Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 4.48, "index_range": null, "line_index": 0, "start": 4.48, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 179.2, "index_range": null, "line_index": 29, "start": 178.56, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 197.00850340136054 }, { "id": "ff50012e-ad1b-4b71-8d0e-6a633428a54f", "title": "Bright", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3a8378d5-94d4-49b7-9c0a-8432c0c4a39d/image/ff50012e-ad1b-4b71-8d0e-6a633428a54f.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/3a8378d5-94d4-49b7-9c0a-8432c0c4a39d/audio/ff50012e-ad1b-4b71-8d0e-6a633428a54f.m4a", "video_url": null, "created_at": "2025-06-23T02:00:52.795796Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 186.88, "index_range": null, "line_index": 29, "start": 186.24, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 213.85757369614512 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "action": "replace_section", "model": "FUZZ-1.0 Pro", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_id": "b7376272-3902-49b4-a83b-62f7e6ab505c", "replace_section_start": 3, "replace_section_end": 70 }'
{ "success": true, "task_id": "73defcbf-f876-4dd6-b60e-4c1c5ecd4565", "trace_id": "9f639389-7218-4cdb-ade9-b34228bb0f21", "data": [ { "id": "037f5e9d-9da4-4d79-b58f-1f433b40d54d", "title": "Sunrise Joy", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/881ad27f-39c1-4c31-a789-ecc822e13b8c/image/037f5e9d-9da4-4d79-b58f-1f433b40d54d.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/881ad27f-39c1-4c31-a789-ecc822e13b8c/audio/037f5e9d-9da4-4d79-b58f-1f433b40d54d.m4a", "video_url": null, "created_at": "2025-06-23T02:18:43.031184Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 3.84, "index_range": null, "line_index": 0, "start": 3.84, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 159.36, "index_range": null, "line_index": 29, "start": 159.36, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 199.2201133786848 }, { "id": "97638295-068f-4cbc-b076-66f522449bd5", "title": "Sunrise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/881ad27f-39c1-4c31-a789-ecc822e13b8c/image/97638295-068f-4cbc-b076-66f522449bd5.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/881ad27f-39c1-4c31-a789-ecc822e13b8c/audio/97638295-068f-4cbc-b076-66f522449bd5.m4a", "video_url": null, "created_at": "2025-06-23T02:18:56.267775Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 3.84, "index_range": null, "line_index": 0, "start": 3.84, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 159.36, "index_range": null, "line_index": 29, "start": 159.36, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 199.2201133786848 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "action": "swap_sound", "model": "FUZZ-1.0 Pro", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_id": "b7376272-3902-49b4-a83b-62f7e6ab505c" }'
{ "success": true, "task_id": "93279260-5ca1-42d8-bde1-1fa62e0f5027", "trace_id": "bc4e28db-4897-4ffc-9e03-45f43da7a21c", "data": [ { "id": "242035c0-8ac2-4f0b-a19c-ac2fa49d4df3", "title": "Brightside", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/36494e8a-eb82-4d89-bbfa-ec719e19572b/image/242035c0-8ac2-4f0b-a19c-ac2fa49d4df3.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/36494e8a-eb82-4d89-bbfa-ec719e19572b/audio/242035c0-8ac2-4f0b-a19c-ac2fa49d4df3.m4a", "video_url": null, "created_at": "2025-06-23T02:02:32.799561Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 1.28, "index_range": null, "line_index": 0, "start": 1.28, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 195.84, "index_range": null, "line_index": 29, "start": 195.84, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 197.2696371882086 }, { "id": "594fe702-6c71-4b0c-abb6-21b58efc74a6", "title": "Sunrise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/36494e8a-eb82-4d89-bbfa-ec719e19572b/image/594fe702-6c71-4b0c-abb6-21b58efc74a6.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/36494e8a-eb82-4d89-bbfa-ec719e19572b/audio/594fe702-6c71-4b0c-abb6-21b58efc74a6.m4a", "video_url": null, "created_at": "2025-06-23T02:02:30.523279Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 0.64, "index_range": null, "line_index": 0, "start": 0.64, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 192.64, "index_range": null, "line_index": 29, "start": 192.64, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 196.7198866213152 } ] }
curl -X POST 'https://api.acedata.cloud/riffusion/audios' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "action": "swap_vocals", "model": "FUZZ-1.0 Pro", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_id": "b7376272-3902-49b4-a83b-62f7e6ab505c" }'
{ "success": true, "task_id": "a6e0d456-189b-4c78-9232-2fe72166ab39", "trace_id": "ee5769d4-ae94-4e5a-a85f-b3c0ddc2e48e", "data": [ { "id": "b8b1ed14-f43c-4738-a697-60ba24b6049d", "title": "Uplift", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/25ce4ddd-e48c-42e2-9ea3-8e03380508f2/image/b8b1ed14-f43c-4738-a697-60ba24b6049d.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/25ce4ddd-e48c-42e2-9ea3-8e03380508f2/audio/b8b1ed14-f43c-4738-a697-60ba24b6049d.m4a", "video_url": null, "created_at": "2025-06-23T02:04:18.477032Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 2.56, "index_range": null, "line_index": 0, "start": 2.56, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 186.88, "index_range": null, "line_index": 29, "start": 171.52, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 195.55968253968254 }, { "id": "dfd6eb9c-a1f3-4e1f-bbf9-e0b9625e459f", "title": "Vivid Rise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/25ce4ddd-e48c-42e2-9ea3-8e03380508f2/image/dfd6eb9c-a1f3-4e1f-bbf9-e0b9625e459f.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/25ce4ddd-e48c-42e2-9ea3-8e03380508f2/audio/dfd6eb9c-a1f3-4e1f-bbf9-e0b9625e459f.m4a", "video_url": null, "created_at": "2025-06-23T02:04:27.140387Z", "model": null, "lyrics_timestamped": { "words": [ { "end": 1.28, "index_range": null, "line_index": 0, "start": 1.28, "text": "[Verse]", "wav2vec2_format": null }, ... { "end": 188.8, "index_range": null, "line_index": 29, "start": 188.16, "text": "high", "wav2vec2_format": null } ] }, "state": "succeeded", "style": "", "duration": 196.07185941043085 } ] }
異步回調(diào)
由于 Riffusion Audios Generation API 生成的時(shí)間有時(shí)候會(huì)相對(duì)較長(zhǎng),如果 API 長(zhǎng)時(shí)間無(wú)響應(yīng),HTTP 請(qǐng)求會(huì)一直保持連接,導(dǎo)致額外的系統(tǒng)資源消耗,所以本 API 也提供了異步回調(diào)的支持。
整體流程是:客戶端發(fā)起請(qǐng)求的時(shí)候,額外指定一個(gè) callback_url 字段,客戶端發(fā)起 API 請(qǐng)求之后,API 會(huì)立馬返回一個(gè)結(jié)果,包含一個(gè) task_id 的字段信息,代表當(dāng)前的任務(wù) ID。當(dāng)任務(wù)完成之后,生成任務(wù)的結(jié)果會(huì)通過(guò) POST JSON 的形式發(fā)送到客戶端指定的 callback_url,其中也包括了 task_id 字段,這樣任務(wù)結(jié)果就可以通過(guò) ID 關(guān)聯(lián)起來(lái)了。
{ "success": true, "task_id": "9939767a-7f9c-4f43-aabf-ca68fe385f3c", "trace_id": "13a86870-e705-45d0-8447-82a08701c0fa", "data": [ { "id": "72e6c476-0116-4da9-ae34-f78190020b35", "title": "Rise", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/9b9f3281-6b47-44ac-8e4b-3b0d105e163d/image/72e6c476-0116-4da9-ae34-f78190020b35.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/9b9f3281-6b47-44ac-8e4b-3b0d105e163d/audio/72e6c476-0116-4da9-ae34-f78190020b35.m4a", "video_url": null, "created_at": "2025-06-15T15:43:22.432605Z", "model": "FUZZ-1.0", "state": "succeeded", "style": "acoustic folk, finger picking", "duration": 184.96 }, { "id": "7f4f5c20-4395-4583-9dbb-735b9bb86957", "title": "Luminance", "image_url": "https://storage.googleapis.com/corpusant-app-public/riffs/9b9f3281-6b47-44ac-8e4b-3b0d105e163d/image/7f4f5c20-4395-4583-9dbb-735b9bb86957.jpg", "lyric": "[Verse]\nWoke up with the sun in my eyes\nNo clouds above just blue in the skies\nShoes on my feet I’m ready to run\nEvery step feels like a loaded gun\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Verse 2]\nDancing through the city streets\nA rhythm pounding in my heartbeat\nStrangers smile it’s catching on\nThis world’s a stage we’re all a song\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high\n[Bridge]\nThrow your worries out the door\nLet them sink to the ocean floor\nWe’re alive and it’s enough\nLife is messy but it’s love\n[Chorus]\nHappy days are rolling in\nLet the joy beneath my skin\nNo more shadows no more lies\nJust the truth that lifts me high", "audio_url": "https://storage.googleapis.com/corpusant-app-public/riffs/9b9f3281-6b47-44ac-8e4b-3b0d105e163d/audio/7f4f5c20-4395-4583-9dbb-735b9bb86957.m4a", "video_url": null, "created_at": "2025-06-15T15:43:21.574561Z", "model": "FUZZ-1.0", "state": "succeeded", "style": "deep bass, ethereal electronic", "duration": 165.12 } ] }
通過(guò)本文檔,您已經(jīng)了解了如何使用 人臉年齡變化 API 對(duì)輸入的圖片和年齡信息來(lái)進(jìn)行人臉年齡變化。希望本文檔能幫助您更好地對(duì)接和使用該 API。如有任何問(wèn)題,請(qǐng)隨時(shí)聯(lián)系我們的技術(shù)支持團(tuán)隊(duì)。
我們還可以通過(guò) position 參數(shù)控制二維碼的位置,比如說(shuō)一張圖片里面有一個(gè)女生穿裙子,而我們想要把二維碼放在裙子的位置并與之融合起來(lái),我們就可以嘗試改下二維碼的位置,調(diào)用樣例如下:
1 2 3 4 5 6 7 8 9 10
curl -X POST "https://api.zhishuyun.com/qrart/generate?token={token}" \ -H "accept: application/json" \ -H "content-type: application/json" \ -d '{ "type": "link", "content": "https://data.zhishuyun.com", "prompt": "one of the beautiful girls in the moonlight in the background, in the style of pixelated chaos, rococo-inspired art, dark white and sky-blue, made of plastic, delicate flowers, gongbi, wimmelbilder", "position": "bottom", "aspect_ratio": "576x1008" }'
隨著 AI 的應(yīng)用變廣,各類 AI 程序已逐漸普及。AI 已逐漸深入到人們的工作生活方方面面。而 AI 涉及的行業(yè)也越來(lái)越多,從最初的寫作,到醫(yī)療教育,再到現(xiàn)在的視頻。
Luma 是一個(gè)專業(yè)高質(zhì)量的視頻生成平臺(tái),用戶只需上傳素材,即可根據(jù)不同風(fēng)格和效果自動(dòng)生成高質(zhì)量視頻。該 AI 視頻生成器由來(lái)自知名科技公司的團(tuán)隊(duì)成員開(kāi)發(fā),目標(biāo)是無(wú)需復(fù)雜的編輯工具,讓每個(gè)人都能輕松制作出色的視頻。
由于 Luma 生成視頻的時(shí)間相對(duì)較長(zhǎng),大約需要 1-2 分鐘,如果 API 長(zhǎng)時(shí)間無(wú)響應(yīng),HTTP 請(qǐng)求會(huì)一直保持連接,導(dǎo)致額外的系統(tǒng)資源消耗,所以本 API 也提供了異步回調(diào)的支持。
整體流程是:客戶端發(fā)起請(qǐng)求的時(shí)候,額外指定一個(gè) callback_url 字段,客戶端發(fā)起 API 請(qǐng)求之后,API 會(huì)立馬返回一個(gè)結(jié)果,包含一個(gè) task_id 的字段信息,代表當(dāng)前的任務(wù) ID。當(dāng)任務(wù)完成之后,生成音樂(lè)的結(jié)果會(huì)通過(guò) POST JSON 的形式發(fā)送到客戶端指定的 callback_url,其中也包括了 task_id 字段,這樣任務(wù)結(jié)果就可以通過(guò) ID 關(guān)聯(lián)起來(lái)了。
Nexior 是 GitHub 上的一個(gè)開(kāi)源項(xiàng)目,利用它我們可以一鍵部署自己的 AI 應(yīng)用站點(diǎn),包括 AI 問(wèn)答、Midjourney 繪畫、知識(shí)庫(kù)問(wèn)答、藝術(shù)二維碼等應(yīng)用,無(wú)需自己開(kāi)發(fā) AI 系統(tǒng)、無(wú)需采購(gòu) AI 賬號(hào)、無(wú)需關(guān)心 API 支持、無(wú)需配置支付系統(tǒng),零啟動(dòng)成本,無(wú)風(fēng)險(xiǎn)通過(guò) AI 賺取收益。
本文章會(huì)介紹 Nexior 項(xiàng)目在 Vercel 上的部署流程,無(wú)需任何編程技巧即可幾分鐘部署一套屬于自己的 AI 站點(diǎn),并輕松利用該站點(diǎn)獲取收益。
隨著 AI 的應(yīng)用變廣,各類 AI 程序已逐漸普及。AI 已逐漸深入到人們的工作生活方方面面。而 AI 涉及的行業(yè)也越來(lái)越多,從最初的寫作,到醫(yī)療教育,再到現(xiàn)在的音樂(lè)。
Suno 是一個(gè)專業(yè)高質(zhì)量的 AI 歌曲和音樂(lè)創(chuàng)作平臺(tái),用戶只需輸入簡(jiǎn)單的文本提示詞,即可根據(jù)流派風(fēng)格和歌詞生成帶有人聲的歌曲。該 AI 音樂(lè)生成器由來(lái)自 Meta、TikTok、Kensho 等知名科技公司的團(tuán)隊(duì)成員開(kāi)發(fā),目標(biāo)是不需要任何樂(lè)器工具,讓所有人都可以創(chuàng)造美妙的音樂(lè)。
{ "success": true, "data": [ { "id": "2f16f7bc-4135-42c6-b3c5-6d6c49dc8cd5", "title": "Winter Wonderland", "image_url": "https://cdn1.suno.ai/image_2f16f7bc-4135-42c6-b3c5-6d6c49dc8cd5.png", "lyric": "[Verse]\nSnowflakes falling all around\nGlistening white\nCovering the ground\nChildren laughing\nFull of delight\nIn this winter wonderland tonight\nSanta's sleigh\nUp in the sky\nRudolph's nose shining bright\nOh my\nHear the jingle bells\nRinging so clear\nBringing joy and holiday cheer\n[Verse 2]\nRoasting chestnuts by the fire's glow\nChristmas lights\nThey twinkle and show\nFamilies gathering with love and cheer\nSpreading warmth to everyone near", "audio_url": "https://cdn1.suno.ai/2f16f7bc-4135-42c6-b3c5-6d6c49dc8cd5.mp3", "video_url": "https://cdn1.suno.ai/2f16f7bc-4135-42c6-b3c5-6d6c49dc8cd5.mp4", "created_at": "2024-05-10T16:21:37.624Z", "model": "chirp-v3", "prompt": "A song for Christmas", "style": "holiday" }, { "id": "5dca232b-17cc-4896-a2d1-4b59178bf410", "title": "Winter Wonderland", "image_url": "https://cdn1.suno.ai/image_5dca232b-17cc-4896-a2d1-4b59178bf410.png", "lyric": "[Verse]\nSnowflakes falling all around\nGlistening white\nCovering the ground\nChildren laughing\nFull of delight\nIn this winter wonderland tonight\nSanta's sleigh\nUp in the sky\nRudolph's nose shining bright\nOh my\nHear the jingle bells\nRinging so clear\nBringing joy and holiday cheer\n[Verse 2]\nRoasting chestnuts by the fire's glow\nChristmas lights\nThey twinkle and show\nFamilies gathering with love and cheer\nSpreading warmth to everyone near", "audio_url": "https://cdn1.suno.ai/5dca232b-17cc-4896-a2d1-4b59178bf410.mp3", "video_url": "https://cdn1.suno.ai/5dca232b-17cc-4896-a2d1-4b59178bf410.mp4", "created_at": "2024-05-10T16:21:37.624Z", "model": "chirp-v3", "prompt": "A song for Christmas", "style": "holiday" } ] }
[Verse]\nSnowflakes falling all around\nGlistening white\nCovering the ground\nChildren laughing\nFull of delight\nIn this winter wonderland tonight\nSanta's sleigh\nUp in the sky\nRudolph's nose shining bright\nOh my\nHear the jingle bells\nRinging so clear\nBringing joy and holiday cheer\n[Verse 2]\nRoasting chestnuts by the fire's glow\nChristmas lights\nThey twinkle and show\nFamilies gathering with love and cheer\nSpreading warmth to everyone near
注意,這里的歌詞中 \n 是換行符,如果你不知道如何生成歌詞,可以使用下文介紹的生成歌詞的 API 自助生成。
curl -X POST 'https://api.acedata.cloud/suno/audios' \ -H 'authorization: Bearer {token}' \ -H 'accept: application/json' \ -H 'content-type: application/json' \ -d '{ "lyric": "[Verse]\\nSnowflakes falling all around\\nGlistening white\\nCovering the ground\\nChildren laughing\\nFull of delight\\nIn this winter wonderland tonight\\nSanta's sleigh\\nUp in the sky\\nRudolph's nose shining bright\\nOh my\\nHear the jingle bells\\nRinging so clear\\nBringing joy and holiday cheer\\n[Verse 2]\\nRoasting chestnuts by the fire's glow\\nChristmas lights\\nThey twinkle and show\\nFamilies gathering with love and cheer\\nSpreading warmth to everyone near", "custom": true }'
測(cè)試允許,生成的效果是類似的。
異步回調(diào)
由于 Suno 生成音樂(lè)的時(shí)間相對(duì)較長(zhǎng),大約需要 1-2 分鐘,如果 API 長(zhǎng)時(shí)間無(wú)響應(yīng),HTTP 請(qǐng)求會(huì)一直保持連接,導(dǎo)致額外的系統(tǒng)資源消耗,所以本 API 也提供了異步回調(diào)的支持。
整體流程是:客戶端發(fā)起請(qǐng)求的時(shí)候,額外指定一個(gè) callback_url 字段,客戶端發(fā)起 API 請(qǐng)求之后,API 會(huì)立馬返回一個(gè)結(jié)果,包含一個(gè) task_id 的字段信息,代表當(dāng)前的任務(wù) ID。當(dāng)任務(wù)完成之后,生成音樂(lè)的結(jié)果會(huì)通過(guò) POST JSON 的形式發(fā)送到客戶端指定的 callback_url,其中也包括了 task_id 字段,這樣任務(wù)結(jié)果就可以通過(guò) ID 關(guān)聯(lián)起來(lái)了。
{ "success": true, "task_id": "44472ab8-783b-4054-b861-5bf14e462f60", "data": [ { "id": "da4324e5-84b2-484b-b0e9-dd261381c594", "title": "Winter Whispers", "image_url": "https://cdn1.suno.ai/image_da4324e5-84b2-484b-b0e9-dd261381c594.png", "lyric": "[Verse]\nSnow falling gently from the sky\nChildren giggling as they pass by\nFire crackling\nCozy and warm\nChristmas spirit begins to swarm\n[Verse 2]\nTwinkling lights\nA sight to behold\nStockings hung\nWaiting to be filled with gold\nGifts wrapped with love\nPiled high\nExcitement in the air\nYou can't deny\n[Chorus]\nWinter whispers in the wind\nJoy and love it brings\nLet's celebrate this season\nWith the ones we're missing", "audio_url": "https://cdn1.suno.ai/da4324e5-84b2-484b-b0e9-dd261381c594.mp3", "video_url": "https://cdn1.suno.ai/da4324e5-84b2-484b-b0e9-dd261381c594.mp4", "created_at": "2024-05-11T07:33:05.430Z", "model": "chirp-v3", "prompt": "A song for Christmas", "style": "pop" }, { "id": "b878a87b-a0db-4046-8ccd-ecd2fb3d4372", "title": "Winter Whispers", "image_url": "https://cdn1.suno.ai/image_b878a87b-a0db-4046-8ccd-ecd2fb3d4372.png", "lyric": "[Verse]\nSnow falling gently from the sky\nChildren giggling as they pass by\nFire crackling\nCozy and warm\nChristmas spirit begins to swarm\n[Verse 2]\nTwinkling lights\nA sight to behold\nStockings hung\nWaiting to be filled with gold\nGifts wrapped with love\nPiled high\nExcitement in the air\nYou can't deny\n[Chorus]\nWinter whispers in the wind\nJoy and love it brings\nLet's celebrate this season\nWith the ones we're missing", "audio_url": "https://cdn1.suno.ai/b878a87b-a0db-4046-8ccd-ecd2fb3d4372.mp3", "video_url": "https://cdn1.suno.ai/b878a87b-a0db-4046-8ccd-ecd2fb3d4372.mp4", "created_at": "2024-05-11T07:33:05.430Z", "model": "chirp-v3", "prompt": "A song for Christmas", "style": "pop" } ] }
這里我們輸入的 prompt 是 A song about winter,生成和冬天相關(guān)的歌曲。
點(diǎn)擊運(yùn)行,結(jié)果如下:
1 2 3 4 5 6 7 8 9
{ "success": true, "task_id": "57e8ce3a-39cb-41a2-802f-e70a324f4d0a", "data": { "text": "[Verse]\nSnowflakes falling from the sky\nWinter's cold touch\nOh how it gets me high\nI bundle up in layers\nOh so cozy\nStepping out and feeling the frost on my nose\nSee\n\n[Verse 2]\nThe world is covered in a blanket of white\nIcicles hanging\nShimmering so bright\nThe chilly air fills my lungs with every breath\nWalking in the snow\nLeaving footprints that won't be left\n\n[Chorus]\nOh\nWinter's cold touch\nIt's a season that I love so much\nSnowfall brings a feeling so divine\nWinter's cold touch\nIt's a magical time", "title": "Winter's Cold Touch", "status": "complete" } }
AceDataCloud 是什么呢?簡(jiǎn)單來(lái)說(shuō),它是一個(gè)提供多樣數(shù)字化 API 的服務(wù)平臺(tái),其官網(wǎng)鏈接是:https://platform.acedata.cloud?inviter_id=aef91f35-f7f9-494d-bcf6-3a533440101f 。
在沒(méi)開(kāi)啟流式輸出的情況下,本 API 從發(fā)起請(qǐng)求到返回結(jié)果,實(shí)際上是從上述「發(fā)送命令」->「生圖完畢」的全過(guò)程,中間生圖的過(guò)程也全被包含在里面,由于 Midjourney 本身生成圖片速度較慢,整個(gè)過(guò)程大約需要等待一分鐘或更久。
所以為了更好的用戶體驗(yàn),本 API 支持流式輸出,即當(dāng)「開(kāi)始生圖」的時(shí)候就開(kāi)始返回結(jié)果,每當(dāng)繪制進(jìn)度有變化,就會(huì)流式將結(jié)果輸出,直至生圖結(jié)束。
{ "answer": "I am an AI language model developed by OpenAI and I don't have a personal name. However, you can call me GPT or simply Chatbot. How can I assist you today?" }
{ "answer": "I am an AI language model created by OpenAI and I don't have a personal name. You can simply call me OpenAI or ChatGPT. How can I assist you today?", "id": "7cdb293b-2267-4979-a1ec-48d9ad149916" }
第二次請(qǐng)求,將第一次請(qǐng)求返回的 id 字段作為參數(shù)傳遞,同時(shí) stateful 參數(shù)依然設(shè)置為 true,詢問(wèn)「What I asked you just now?」,如圖所示:
對(duì)應(yīng)代碼如下:
1 2 3 4 5 6 7 8 9 10
curl -X POST 'https://api.acedata.cloud/aichat/conversations' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "gpt-3.5", "stateful": true, "id": "7cdb293b-2267-4979-a1ec-48d9ad149916", "question": "What I asked you just now?" }'
結(jié)果如下:
1 2 3 4
{ "answer": "You asked me what my name is. As an AI language model, I do not possess a personal identity, so I don't have a specific name. However, you can refer to me as OpenAI or ChatGPT, the names used for this AI model. Is there anything else I can help you with?", "id": "7cdb293b-2267-4979-a1ec-48d9ad149916" }
@Override publicvoidonResponse(Call call, Response response)throws IOException { if (!response.isSuccessful()) thrownew IOException("Unexpected code " + response); try (BufferedReader br = new BufferedReader( new InputStreamReader(response.body().byteStream(), "UTF-8"))) { String responseLine; while ((responseLine = br.readLine()) != null) { System.out.println(responseLine); } } } });
其他語(yǔ)言可以另外自行改寫,原理都是一樣的。
模型預(yù)設(shè)
我們知道,OpenAI 相關(guān)的 API 有對(duì)應(yīng)的 system_prompt 的概念,就是給整個(gè)模型設(shè)置一個(gè)預(yù)設(shè),比如它叫什么名字等等。本 AI 問(wèn)答 API 也暴露了這個(gè)參數(shù),叫做 preset,利用它我們可以給模型增加預(yù)設(shè),我們用一個(gè)例子來(lái)體驗(yàn)下:
這里我們額外添加 preset 字段,內(nèi)容為 You are a professional artist,如圖所示:
對(duì)應(yīng)代碼如下:
1 2 3 4 5 6 7 8 9 10
curl -X POST 'https://api.acedata.cloud/aichat/conversations' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "gpt-3.5", "stateful": true, "question": "What can you help me?", "preset": "You are a professional artist" }'
運(yùn)行結(jié)果如下:
1 2 3
{ "answer": "As a professional artist, I can offer a range of services and assistance depending on your specific needs. Here are a few ways I can help you:\n\n1. Custom Artwork: If you have a specific vision or idea, I can create custom artwork for you. This can include paintings, drawings, digital art, or any other medium you prefer.\n\n2. Commissioned Pieces: If you have a specific subject or concept in mind, I can create commissioned art pieces tailored to your preferences. This could be for personal enjoyment or as a unique gift for someone special.\n\n3. Art Consultation: If you need guidance on art selection, interior design, or how to showcase and display art in your space, I can provide professional advice to help enhance your aesthetic sense and create a cohesive look." }
curl -X POST 'https://api.acedata.cloud/aichat/conversations' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "gpt-4-vision", "question": "How many apples in the picture?", "references": ["https://cdn.acedata.cloud/ht05g0.png"] }'
運(yùn)行結(jié)果如下:
1 2 3
{ "answer": "There are 5 apples in the picture." }
可以看到,我們就成功得到了對(duì)應(yīng)圖片的回答結(jié)果。
聯(lián)網(wǎng)問(wèn)答
本 API 還支持聯(lián)網(wǎng)模型,包括 GPT-3.5、GPT-4 均能支持,在 API 背后有一個(gè)自動(dòng)搜索互聯(lián)網(wǎng)并總結(jié)的過(guò)程,我們可以選擇模型為 gpt-3.5-browsing 來(lái)體驗(yàn)下,如圖所示:
代碼如下:
1 2 3 4 5 6 7 8
curl -X POST 'https://api.acedata.cloud/aichat/conversations' \ -H 'accept: application/json' \ -H 'authorization: Bearer {token}' \ -H 'content-type: application/json' \ -d '{ "model": "gpt-3.5-browsing", "question": "What's the weather of New York today?" }'
運(yùn)行結(jié)果如下:
1 2 3
{ "answer": "The weather in New York today is as follows:\n- Current Temperature: 16°C (60°F)\n- High: 16°C (60°F)\n- Low: 10°C (50°F)\n- Humidity: 47%\n- UV Index: 6 of 11\n- Sunrise: 5:42 am\n- Sunset: 8:02 pm\n\nIt's overcast with a chance of occasional showers overnight, and the chance of rain is 50%.\nFor more details, you can visit [The Weather Channel](https://weather.com/weather/tenday/l/96f2f84af9a5f5d452eb0574d4e4d8a840c71b05e22264ebdc0056433a642c84).\n\nIs there anything else you'd like to know?" }
可以看到,這里它自動(dòng)聯(lián)網(wǎng)搜索了 The Weather Channel 網(wǎng)站,并獲得了里面的信息,然后進(jìn)一步返回了實(shí)時(shí)結(jié)果。
在這個(gè)數(shù)字化時(shí)代,人工智能技術(shù)正以驚人的速度改變著我們的生活方式和創(chuàng)造方式。音樂(lè)作為一種最直接、最感性的藝術(shù)形式,自然也成為了人工智能技術(shù)的應(yīng)用場(chǎng)景之一。今天,我們將以 Vue 和 Node.js 為基礎(chǔ),利用現(xiàn)有的 API 來(lái)快速搭建一個(gè) Suno AI 音樂(lè)站點(diǎn)。讓我們一起探索這個(gè)令人興奮的過(guò)程吧!
<template> <divid="app"> <header> <h1>XiaoZhi AI Music Generator</h1> </header> <main> <divclass="input-container"> <inputtype="text"v-model="musicTitle"placeholder="Enter a prompt for the music"> <button @click="handleGenerateMusic":disabled="loading">生成音樂(lè)</button> </div> <divv-if="loading"class="loading"> Music is being generated for you, please wait... </div>
<divv-if="musicGenerated"class="music-container"> <divv-for="music in generatedMusic":key="music.id"class="music-item"> <h2>{{ music.title }}</h2> <img:src="music.image_url"alt="Music Image"> <pclass="lyric">{{ music.lyric }}</p> <audiocontrolsclass="audio" @play="stopOtherMedia($event)"> <source:src="music.audio_url"type="audio/mpeg"> Your browser does not support the audio element. </audio> <videocontrolsclass="video" @play="stopOtherMedia($event)"> <source:src="music.video_url"type="video/mp4"> Your browser does not support the video element. </video> </div> </div>
一臺(tái)服務(wù)器:同樣的,如果只是需要自己用,可不需要服務(wù)器,如果想要通過(guò)自己的網(wǎng)站賺錢,你還得準(zhǔn)備一臺(tái) linux 服務(wù)器,剛起步,也不要太好的服務(wù)器,一年 100 元左右的就可以了,騰訊云阿里云都可,不過(guò)建議選擇香港的服務(wù)器。
隨著互聯(lián)網(wǎng)的普及和發(fā)展,海外住宅IP的需求日益增加。個(gè)人用戶可以通過(guò)使用海外住宅 IP 來(lái)訪問(wèn)特定地區(qū)的新聞、娛樂(lè)、教育和文化資源,從而獲得更高的訪問(wèn)速度、優(yōu)質(zhì)的用戶體驗(yàn)和更強(qiáng)的網(wǎng)絡(luò)安全性。
對(duì)于企業(yè)而言,海外住宅IP為進(jìn)軍國(guó)際市場(chǎng)提供了重要的支持。通過(guò)了解目標(biāo)市場(chǎng)的需求和競(jìng)爭(zhēng)環(huán)境,企業(yè)可以制定相應(yīng)的營(yíng)銷策略和產(chǎn)品定位。海外住宅 IP 還有助于企業(yè)進(jìn)行市場(chǎng)推廣活動(dòng),實(shí)現(xiàn)定向投放廣告和提供個(gè)性化的客戶體驗(yàn),從而提升品牌知名度和市場(chǎng)份額。
一、海外住宅 IP 的可靠性
海外住宅 IP 的可靠性主要取決于供應(yīng)商的信譽(yù)和服務(wù)質(zhì)量。為了保障用戶的在線安全和隱私,選擇一個(gè)可靠的海外住宅 IP 提供商至關(guān)重要。在此推薦 SmartProxy,一家優(yōu)質(zhì)海外住宅代理和全球IP資源服務(wù)商。SmartProxy 提供穩(wěn)定可靠的服務(wù),而且價(jià)格相對(duì)較為實(shí)惠。注冊(cè)即領(lǐng)免費(fèi)流量:
我們還可以通過(guò) position 參數(shù)控制二維碼的位置,比如說(shuō)一張圖片里面有一個(gè)女生穿裙子,而我們想要把二維碼放在裙子的位置并與之融合起來(lái),我們就可以嘗試改下二維碼的位置,調(diào)用樣例如下:
1 2 3 4 5 6 7 8 9
curl -X POST "https://api.zhishuyun.com/qrart/generate?token={token}" \ -H "accept: application/json" \ -H "content-type: application/json" \ -d '{ "type": "link", "content": "https://data.zhishuyun.com", "prompt": "one of the beautiful girls in the moonlight in the background, in the style of pixelated chaos, rococo-inspired art, dark white and sky-blue, made of plastic, delicate flowers, gongbi, wimmelbilder", "position": "bottom" }'
在這里我們就不再對(duì)各種 API 參數(shù)進(jìn)行一一介紹了,更詳細(xì)更實(shí)時(shí)的內(nèi)容可以參見(jiàn)知數(shù)云的官方文檔,鏈接為:https://data.zhishuyun.com/documents/ee085d2a-a0b9-4f0e-8b4d-8da407345138。
價(jià)格
知數(shù)云藝術(shù)二維碼的 API 提供了階梯定價(jià),首次申請(qǐng)免費(fèi)贈(zèng)送 20 次,而且購(gòu)買越多越便宜,由于價(jià)格會(huì)動(dòng)態(tài)調(diào)整,所以大家可以查看知數(shù)云官網(wǎng)來(lái)查看最新實(shí)時(shí)價(jià)格:https://data.zhishuyun.com/services/38ecf158-36f2-42f2-8e7f-6786cdfc2452
總體來(lái)看,無(wú)論是在 Discord 上使用 Midjourney 提供的哪一項(xiàng)功能,這個(gè) API 都能完全還原官方操作的效果和效能。
穩(wěn)定性如何呢?根據(jù)我個(gè)人幾個(gè)月的觀察和使用經(jīng)驗(yàn),可以毫不夸張地說(shuō),目前業(yè)界很難找到比知數(shù)云 Midjourney API 更穩(wěn)定且并發(fā)處理能力更高的選擇,而且還能保持 Midjourney 這一價(jià)格水平。這樣的選擇寥寥無(wú)幾。
下面我們就來(lái)了解下這個(gè) API 的申請(qǐng)和使用方法吧。
申請(qǐng)流程
下文內(nèi)容大多數(shù)來(lái)源于知數(shù)云 Midjourney API 官方介紹文檔,文檔鏈接:https://data.zhishuyun.com/documents/0fd3dd40-a16a-4246-8313-748b8e75c29e,最新內(nèi)容以官方文檔為準(zhǔn)。
要使用 Midjourney Imagine API,首先可以到 Midjourney Imagine API 頁(yè)面點(diǎn)擊「獲取」按鈕:
依次填寫好圖中所示參數(shù),然后點(diǎn)擊「測(cè)試」按鈕即可測(cè)試接口?!笢y(cè)試」按鈕下方會(huì)顯示 API 返回的結(jié)果。同時(shí)您可以注意到右側(cè)有對(duì)應(yīng)的調(diào)用代碼生成,您可以復(fù)制代碼到您的 IDE 里面進(jìn)行對(duì)接和開(kāi)發(fā)。
在沒(méi)開(kāi)啟流式輸出的情況下,本 API 從發(fā)起請(qǐng)求到返回結(jié)果,實(shí)際上是從上述「發(fā)送命令」->「生圖完畢」的全過(guò)程,中間生圖的過(guò)程也全被包含在里面,由于 Midjourney 本身生成圖片速度較慢,整個(gè)過(guò)程大約需要等待一分鐘或更久。
所以為了更好的用戶體驗(yàn),本 API 支持流式輸出,即當(dāng)「開(kāi)始生圖」的時(shí)候就開(kāi)始返回結(jié)果,每當(dāng)繪制進(jìn)度有變化,就會(huì)流式將結(jié)果輸出,直至生圖結(jié)束。
價(jià)格怎么樣呢?由于價(jià)格可能會(huì)動(dòng)態(tài)變化,大家可以直接參考知數(shù)云的官方網(wǎng)站了解:https://data.zhishuyun.com/services/d87e5e99-b797-4ade-9e73-b896896b0461。但總的來(lái)說(shuō),能夠以這個(gè)價(jià)格做到知數(shù)云 Midjourney API 這樣的穩(wěn)定性和并發(fā)的,業(yè)界寥寥無(wú)幾,歡迎選購(gòu)和評(píng)測(cè)。
這家代理的官方網(wǎng)站是 http://www.ipidea.net/?utm-source=cqc&utm-keyword=?ipidea。從他們的介紹可以看到,他們是一家全球范圍的 IP 代理服務(wù)商,能覆蓋全球 220 個(gè)國(guó)家和地區(qū),大部分代理實(shí)際上是住宅 IP。
官方介紹這家的代理 IP 數(shù)量大約是九千萬(wàn)左右,這個(gè)數(shù)量非常龐大,同時(shí)官方介紹說(shuō)代理的可用率是 99.9%。
下面我們來(lái)看一下他們的一些套餐類型:
動(dòng)態(tài)住宅代理:這種代理實(shí)際上就是用真實(shí)的住宅用戶的 IP 搭建的代理。一般來(lái)說(shuō),住宅代理對(duì)于很多場(chǎng)景的使用封禁概率會(huì)比較低,因?yàn)楹芏鄰S商對(duì)封禁住宅代理是比較謹(jǐn)慎的。動(dòng)態(tài)住宅代理其實(shí)就是可以定時(shí)切換的 IP,比如說(shuō)做網(wǎng)絡(luò)爬蟲(chóng),我們就需要不斷變換的不同的代理 IP,這樣可以進(jìn)一步的減少被封禁的概率。
靜態(tài)住宅代理:相對(duì)于動(dòng)態(tài)代理來(lái)說(shuō),靜態(tài)住宅代理的特點(diǎn)就是長(zhǎng)效穩(wěn)定,可以一直獲取一個(gè)穩(wěn)定不變的代理 IP,適合長(zhǎng)久的穩(wěn)定的海外網(wǎng)絡(luò)環(huán)境使用。比如說(shuō),我們要進(jìn)行自動(dòng)化網(wǎng)站的爬取,如果在一個(gè)頁(yè)面內(nèi) IP 地址頻繁變動(dòng)會(huì)增大被風(fēng)控的概率。所以,如果有一個(gè)長(zhǎng)效穩(wěn)定的住宅 IP 代理,就會(huì)非常方便。
數(shù)據(jù)中心代理:這種代理實(shí)際上是很多服務(wù)器廠商的服務(wù)器搭建起來(lái)的代理。例如騰訊云、阿里云、微軟云等服務(wù)器所在的 IP 地址段,就屬于所謂的數(shù)據(jù)中心的 IP 地址段。因此,用這些服務(wù)器搭建出來(lái)的代理就叫做數(shù)據(jù)中心代理。一般來(lái)說(shuō),這種數(shù)據(jù)中心代理相對(duì)于住宅代理更容易被爬蟲(chóng)封禁,但是這種代理的優(yōu)勢(shì)就是價(jià)格更加便宜,而且網(wǎng)絡(luò)速度也會(huì)相對(duì)較好。
一旦服務(wù)運(yùn)行起來(lái),由于代理本身是全球動(dòng)態(tài)或者動(dòng)態(tài)數(shù)據(jù)中心,因此里面的代理 IP 會(huì)動(dòng)態(tài)變化。這樣,對(duì)于單個(gè)賬號(hào)來(lái)說(shuō),每次請(qǐng)求 OpenAI 的 IP 都在變化,就可以解除單個(gè)賬號(hào)訪問(wèn)的限制。
我們剛才討論了通過(guò) API 請(qǐng)求方式的隧道代理設(shè)置,這種方式相對(duì)方便。但在某些情況下,我們實(shí)際上想要的是更穩(wěn)定、長(zhǎng)效的代理,即動(dòng)態(tài)長(zhǎng)效 ISP。
我通常會(huì)將這種代理用于一些模擬登錄服務(wù)。由于我需要使用瀏覽器進(jìn)行這些服務(wù),如果我將瀏覽器設(shè)置為一個(gè)動(dòng)態(tài)切換的隧道代理,那么在一次網(wǎng)頁(yè)請(qǐng)求中,所有請(qǐng)求的 IP 地址都可能是不同的。因此,我們實(shí)際上希望在同一瀏覽器會(huì)話下,IP 地址能夠保持相對(duì)穩(wěn)定。
于是,動(dòng)態(tài)長(zhǎng)效 ISP 就能派上用場(chǎng)。我通常使用模擬瀏覽器驅(qū)動(dòng)的方式來(lái)啟動(dòng)瀏覽器,然后動(dòng)態(tài)設(shè)置代理 IP 為動(dòng)態(tài)長(zhǎng)效 ISP。設(shè)置完成后,我便可以啟動(dòng)瀏覽器進(jìn)行網(wǎng)頁(yè)模擬,比如登錄模擬 GPT 網(wǎng)站等。
I want you to act as a javascript console. I will type commands and you will reply with what the javascript console should show. I want you to only reply with the terminal output inside one unique code block, and nothing else. do not write explanations. do not type commands unless I instruct you to do so. when i need to tell you something in english, i will do so by putting text inside curly brackets {like this}. my first command is console.log(“Hello World”);
corrdinate:一個(gè)返回結(jié)果的控制開(kāi)關(guān),默認(rèn)會(huì)返回每張圖片識(shí)別的 true / false 結(jié)果,也就是第 x 張圖片是否和圖片匹配,如果加上該參數(shù),那么 API 就會(huì)返回對(duì)應(yīng)匹配圖片的索引。
比如這里我們可以 POST 這樣的一個(gè)內(nèi)容給服務(wù)器,結(jié)構(gòu)如下:
import time from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.common.action_chains import ActionChains from app.captcha_resolver import CaptchaResolver
# click captchas recognized_indices = [i for i, x in enumerate(recognized_results) if x] logger.debug(f'recognized_indices {recognized_indices}') click_targets = self.wait.until(EC.visibility_of_all_elements_located( (By.CSS_SELECTOR, '.task-image'))) for recognized_index in recognized_indices: click_target: WebElement = click_targets[recognized_index] click_target.click() time.sleep(random())
import time from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.common.action_chains import ActionChains from app.captcha_resolver import CaptchaResolver
defget_question_id_by_target_name(target_name): logger.debug(f'try to get question id by {target_name}') question_id = CAPTCHA_TARGET_NAME_QUESTION_ID_MAPPING.get(target_name) logger.debug(f'question_id {question_id}') return question_id
single_captcha_elements = self.wait.until(EC.visibility_of_all_elements_located( (By.CSS_SELECTOR, '#rc-imageselect-target table td'))) for recognized_index in recognized_indices: single_captcha_element: WebElement = single_captcha_elements[recognized_index] single_captcha_element.click() # check if need verify single captcha self.verify_single_captcha(recognized_index)
我們其實(shí)可以在每點(diǎn)擊完一個(gè)格子之后就來(lái)校驗(yàn)下當(dāng)前小格子有沒(méi)有圖片刷新,如果有圖片刷新,那么對(duì)應(yīng)的 HTML 的 class 就會(huì)變化,否則就會(huì)包含 selected 字樣,然后我們?cè)倮^續(xù)對(duì)小格子對(duì)應(yīng)的圖進(jìn)行二次識(shí)別就好了。
defverify_single_captcha(self, index): time.sleep(3) elements = self.wait.until(EC.visibility_of_all_elements_located( (By.CSS_SELECTOR, '#rc-imageselect-target table td'))) single_captcha_element: WebElement = elements[index] class_name = single_captcha_element.get_attribute('class') logger.debug(f'verifiying single captcha {index}, class {class_name}') if'selected'in class_name: logger.debug(f'no new single captcha displayed') return logger.debug('new single captcha displayed') single_captcha_url = single_captcha_element.find_element_by_css_selector( 'img').get_attribute('src') logger.debug(f'single_captcha_url {single_captcha_url}') with open(CAPTCHA_SINGLE_IMAGE_FILE_PATH, 'wb') as f: f.write(requests.get(single_captcha_url).content) resized_single_captcha_base64_string = resize_base64_image( CAPTCHA_SINGLE_IMAGE_FILE_PATH, (100, 100)) single_captcha_recognize_result = self.captcha_resolver.create_task( resized_single_captcha_base64_string, get_question_id_by_target_name(self.captcha_target_name)) ifnot single_captcha_recognize_result: logger.error('count not get single captcha recognize result') return has_object = single_captcha_recognize_result.get( 'solution', {}).get('hasObject') if has_object isNone: logger.error('count not get captcha recognized indices') return if has_object isFalse: logger.debug('no more object in this single captcha') return if has_object: single_captcha_element.click() # check for new single captcha self.verify_single_captcha(index)
OK,這里我們定義了一個(gè) verify_single_captcha 方法,然后傳入了格子對(duì)應(yīng)的序號(hào)。接著我們首先嘗試查找格子對(duì)應(yīng)的節(jié)點(diǎn),然后找出對(duì)應(yīng)的 HTML 的 class 屬性。如果沒(méi)有出現(xiàn)新的小圖,那就是這樣的選中狀態(tài),對(duì)應(yīng)的 class 就包含了 selected 字樣,如圖所示:
比如說(shuō),我們有兩臺(tái)主機(jī) A、B,我們最終想實(shí)現(xiàn)在 A 上控制 B。那么如果用正向 Shell,其實(shí)就是在 A 上輸入 B 的連接地址,比如通過(guò) ssh 連接到 B,連接成功之后,我們就可以在 A 上通過(guò)命令控制 B 了。如果用反向 Shell,那就是在 A 上先開(kāi)啟一個(gè)監(jiān)聽(tīng)端口,然后讓 B 去連接 A 的這個(gè)端口,連接成功之后,A 這邊就能通過(guò)命令控制 B 了。
反彈 Shell 有什么用?
還是原來(lái)的例子,我們想用 A 來(lái)控制 B,如果想用 ssh 等命令來(lái)控制,那得輸入 B 的 sshd 地址或者端口對(duì)吧?但是在很多情況下,由于防火墻、安全組、局域網(wǎng)、NAT 等原因,我們實(shí)際上是無(wú)法直接連接到 B 的,比如:
A 雖然有公網(wǎng) IP,但 B 是一個(gè)處于內(nèi)網(wǎng)的機(jī)器,A 就沒(méi)法直接連到 B 上。
B 上開(kāi)了防火墻或者安全組限制,sshd 的服務(wù)端口 22 被封閉了。
B 是一臺(tái)撥號(hào)主機(jī),其 IP 地址經(jīng)常變動(dòng)。
假如 B 被攻擊了,我們想讓 B 向 A 匯報(bào)自己的狀況,那自然就需要 B 主動(dòng)去連接 A。
!(function (a, b) { console.log("result", a, b); })(1, 2);
這里我們先聲明了一個(gè) function,然后接收 a 和 b 兩個(gè)參數(shù),然后把內(nèi)容輸出出來(lái),然后我們把這個(gè) function 用小括號(hào)括起來(lái),這其實(shí)就是一個(gè)方法,可以被直接調(diào)用的,怎么調(diào)用呢?后面再跟上對(duì)應(yīng)的參數(shù)就好了,比如傳入 1 和 2,執(zhí)行結(jié)果如下:
1
result 12
可以看到,這個(gè)自執(zhí)行的方法就被執(zhí)行了。
同理地,crypto-js.min.js 也符合這個(gè)格式,它接收 t 和 e 兩個(gè)參數(shù),t 就是 this,其實(shí)就是瀏覽器中的 window 對(duì)象,e 就是一個(gè) function(用于定義 CryptoJS 的核心內(nèi)容)。
接下來(lái)我們來(lái)看一個(gè)簡(jiǎn)單的網(wǎng)站:https://login1.scrape.center/,這個(gè)網(wǎng)站的結(jié)構(gòu)非常簡(jiǎn)單,就是一個(gè)用戶名密碼登錄。但是不同的是,點(diǎn)擊登錄的時(shí)候,表單提交 POST 的內(nèi)容并不是單純的用戶名和密碼,而是一個(gè)加密后的 token。
網(wǎng)頁(yè)是運(yùn)行在瀏覽器端的,當(dāng)我們?yōu)g覽一個(gè)網(wǎng)頁(yè)時(shí),其 HTML 代碼、 JavaScript 代碼都會(huì)被下載到瀏覽器中執(zhí)行。借助瀏覽器的開(kāi)發(fā)者工具,我們可以看到網(wǎng)頁(yè)在加載過(guò)程中所有網(wǎng)絡(luò)請(qǐng)求的詳細(xì)信息,也能清楚地看到網(wǎng)站運(yùn)行的 HTML 代碼和 JavaScript 代碼,這些代碼中就包含了網(wǎng)站加載的全部邏輯,如加載哪些資源、請(qǐng)求接口是如何構(gòu)造的、頁(yè)面是如何渲染的等等。正因?yàn)榇a是完全透明的,所以如果我們能夠把其中的執(zhí)行邏輯研究出來(lái),就可以模擬各個(gè)網(wǎng)絡(luò)請(qǐng)求進(jìn)行數(shù)據(jù)爬取了。
網(wǎng)站運(yùn)營(yíng)者首先想到防護(hù)措施可能是對(duì)某些數(shù)據(jù)接口的參數(shù)進(jìn)行加密,比如說(shuō)對(duì)某些 URL 的一些參數(shù)加上校驗(yàn)碼或者把一些 id 信息進(jìn)行編碼,使其變得難以閱讀或構(gòu)造;或者對(duì)某些 API 請(qǐng)求加上一些 token、sign 等簽名,這樣這些請(qǐng)求發(fā)送到服務(wù)器時(shí),服務(wù)器會(huì)通過(guò)客戶端發(fā)來(lái)的一些請(qǐng)求信息以及雙方約定好的秘鑰等來(lái)對(duì)當(dāng)前的請(qǐng)求進(jìn)行校驗(yàn),如果校驗(yàn)通過(guò),才返回對(duì)應(yīng)數(shù)據(jù)結(jié)果。
現(xiàn)在絕大多數(shù)網(wǎng)站的數(shù)據(jù)一般都是通過(guò)服務(wù)器提供的 API 來(lái)獲取的,網(wǎng)站或 App 可以請(qǐng)求某個(gè)數(shù)據(jù) API 獲取到對(duì)應(yīng)的數(shù)據(jù),然后再把獲取的數(shù)據(jù)展示出來(lái)。但有些數(shù)據(jù)是比較寶貴或私密的,這些數(shù)據(jù)肯定是需要一定層面上的保護(hù)。所以不同 API 的實(shí)現(xiàn)也就對(duì)應(yīng)著不同的安全防護(hù)級(jí)別,我們這里來(lái)總結(jié)下。
var a = ["hello"]; (function (c, d) { var e = function (f) { while (--f) { c["push"](c["shift"]()); } }; e(++d); })(a, 0x9b); var b = function (c, d) { c = c - 0x0; var e = a[c]; return e; }; let hello = "1" + 0x1; console["log"](b("0x0"), hello);
const _0x16c18d = function () { if (!![[]]) { console.log("hello world"); } else { console.log("this"); console.log("is"); console.log("dead"); console.log("code"); } }; const _0x1f7292 = function () { if ("xmv2nOdfy2N".charAt(4) !== String.fromCharCode(110)) { console.log("this"); console.log("is"); console.log("dead"); console.log("code"); } else { console.log("nice to meet you"); } };
_0x16c18d(); _0x1f7292();
可以看到,每個(gè)方法內(nèi)部都增加了額外的 if else 語(yǔ)句,其中 if 的判斷條件還是一個(gè)表達(dá)式,其結(jié)果是 true 還是 false 我們還不太一眼能看出來(lái),比如說(shuō) _0x1f7292 這個(gè)方法,它的 if 判斷條件是:
之前我們是用 Elements 面板來(lái)審查頁(yè)面的節(jié)點(diǎn)信息的,我們可以查看當(dāng)前頁(yè)面的 HTML 源代碼及其在網(wǎng)頁(yè)中對(duì)應(yīng)的位置,查看某個(gè)條目的標(biāo)題對(duì)應(yīng)的頁(yè)面源代碼,如圖所示。
這時(shí)候我們可以看到頁(yè)面中顯示了一個(gè)叫作 Paused in debugger 的提示,這說(shuō)明瀏覽器執(zhí)行到剛才我們?cè)O(shè)置斷點(diǎn)的位置處就不再繼續(xù)執(zhí)行了,等待我們發(fā)號(hào)施令執(zhí)行調(diào)試。
此時(shí)代碼停在了第 4446 行,回調(diào)參數(shù) e 就是對(duì)應(yīng)的點(diǎn)擊事件 MouseEvent 。在右側(cè)的 Scope 面板處,可以觀察到各個(gè)變量的值,比如在 Local 域下有當(dāng)前方法的局部變量,我們可以在這里看到 MouseEvent 的各個(gè)屬性,如圖所示。
另外我們關(guān)注到有一個(gè)方法 o,它在 Jr 方法下面,所以切換到 Closure(Jr) 域可以查看它的定義及其接收的參數(shù),如圖所示。
我們可以看到,FunctionLocation 又指向了方法 o ,點(diǎn)擊之后便又可以跳到指定位置,用同樣的方式進(jìn)行斷點(diǎn)調(diào)試即可。
正如我們所料,我們成功將變量 a 輸出,其中的 data 字段就是 Ajax 的 Response 結(jié)果,證明改寫 JavaScript 成功!而且刷新頁(yè)面也不會(huì)丟失了。
我們還可以增加一些 JavaScript 邏輯,比如直接將變量 a 的結(jié)果通過(guò) API 發(fā)送到遠(yuǎn)程服務(wù)器,并通過(guò)服務(wù)器將數(shù)據(jù)保存下來(lái),也就完成了直接攔截 Ajax 請(qǐng)求并保存數(shù)據(jù)的過(guò)程了。
我們?cè)谇懊鎳L試維護(hù)過(guò)一個(gè)代理池,代理池可以挑選出許多可用代理,但是常常其穩(wěn)定性不高、響應(yīng)速度慢,而且這些代理通常是公共代理,可能不止一人同時(shí)使用,其 IP 被封的概率很大。另外,這些代理可能有效時(shí)間比較短,雖然代理池一直在篩選,但如果沒(méi)有及時(shí)更新?tīng)顟B(tài),也有可能獲取到不可用的代理。
ADSL,英文全稱是 Asymmetric Digital Subscriber Line,即非對(duì)稱數(shù)字用戶環(huán)路。它的上行和下行帶寬不對(duì)稱,它采用頻分復(fù)用技術(shù)把普通的電話線分成了電話、上行和下行 3 個(gè)相對(duì)獨(dú)立的信道,從而避免了相互之間的干擾。
ADSL 通過(guò)撥號(hào)的方式上網(wǎng),撥號(hào)時(shí)需要輸入 ADSL 賬號(hào)和密碼,每次撥號(hào)就更換一個(gè) IP。IP 分布在多個(gè) A 段,如果 IP 都能使用,則意味著 IP 量級(jí)可達(dá)千萬(wàn)。如果我們將 ADSL 主機(jī)作為代理,每隔一段時(shí)間云主機(jī)撥號(hào)就換一個(gè) IP,這樣可以有效防止 IP 被封禁。另外,由于我們是直接使用專有的云主機(jī)搭建的代理服務(wù),所以其代理的穩(wěn)定性相對(duì)更好,代理響應(yīng)速度也相對(duì)更快。
可以看到返回結(jié)果的 origin 字段的 IP 就和 ifconfig 獲取的 IP 地址是一致的。
接下來(lái),我們?cè)谧约罕緳C(jī)上(非云主機(jī))運(yùn)行如下命令測(cè)試下代理的連通情況,這里 IP 就需要更換為云主機(jī)本身的 IP 了,剛才可以看到云主機(jī)當(dāng)前撥號(hào)的 IP 是 106.45.104.166,所以需要運(yùn)行如下命令:
那怎么使用代理呢?我們可以在任意可以公網(wǎng)訪問(wèn)的云主機(jī)上連接剛才的 Redis 數(shù)據(jù)庫(kù)并搭建一個(gè) API 服務(wù)即可。怎么搭建呢?我們可以同樣使用剛才的 adslproxy 庫(kù),該庫(kù)也提供了 API 服務(wù)的功能。
最后,我們將 API 服務(wù)部署一下,這個(gè) ADSL 代理服務(wù)就可以像代理池一樣被使用了,每請(qǐng)求一次 API 就可以獲取一個(gè)實(shí)時(shí)可用代理,不同的時(shí)間段這個(gè)代理就會(huì)實(shí)時(shí)更換,而且連接穩(wěn)定速度又快,實(shí)在是網(wǎng)絡(luò)爬蟲(chóng)的最佳搭檔。
接口模塊:需要用 API 來(lái)提供對(duì)外服務(wù)的接口。其實(shí)我們可以直接連接數(shù)據(jù)庫(kù)來(lái)取對(duì)應(yīng)的數(shù)據(jù),但是這樣就需要知道數(shù)據(jù)庫(kù)的連接信息,并且要配置連接,而比較安全和方便的方式就是提供一個(gè) Web API 接口,我們通過(guò)訪問(wèn)接口即可拿到可用代理。另外,由于可用代理可能有多個(gè),所以我們可以設(shè)置一個(gè)隨機(jī)返回某個(gè)可用代理的接口,這樣就能保證每個(gè)可用代理都可以取到,實(shí)現(xiàn)負(fù)載均衡。
import redis from proxypool.exceptions import PoolEmptyException from proxypool.schemas.proxy import Proxy from proxypool.setting import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_KEY, PROXY_SCORE_MAX, PROXY_SCORE_MIN, \ PROXY_SCORE_INIT from random import choice from typing import List from loguru import logger from proxypool.utils.proxy import is_valid_proxy, convert_proxy_or_proxies
defadd(self, proxy: Proxy, score=PROXY_SCORE_INIT) -> int: """ add proxy and set it to init score :param proxy: proxy, ip:port, like 8.8.8.8:88 :param score: int score :return: result """ ifnot is_valid_proxy(f'{proxy.host}:{proxy.port}'): logger.info(f'invalid proxy {proxy}, throw it') return ifnot self.exists(proxy): if IS_REDIS_VERSION_2: return self.db.zadd(REDIS_KEY, score, proxy.string()) return self.db.zadd(REDIS_KEY, {proxy.string(): score})
defrandom(self) -> Proxy: """ get random proxy firstly try to get proxy with max score if not exists, try to get proxy by rank if not exists, raise error :return: proxy, like 8.8.8.8:8 """ # try to get proxy with max score proxies = self.db.zrangebyscore(REDIS_KEY, PROXY_SCORE_MAX, PROXY_SCORE_MAX) if len(proxies): return convert_proxy_or_proxies(choice(proxies)) # else get proxy by rank proxies = self.db.zrevrange(REDIS_KEY, PROXY_SCORE_MIN, PROXY_SCORE_MAX) if len(proxies): return convert_proxy_or_proxies(choice(proxies)) # else raise error raise PoolEmptyException
defdecrease(self, proxy: Proxy) -> int: """ decrease score of proxy, if small than PROXY_SCORE_MIN, delete it :param proxy: proxy :return: new score """ score = self.db.zscore(REDIS_KEY, proxy.string()) # current score is larger than PROXY_SCORE_MIN if score and score > PROXY_SCORE_MIN: logger.info(f'{proxy.string()} current score {score}, decrease 1') if IS_REDIS_VERSION_2: return self.db.zincrby(REDIS_KEY, proxy.string(), -1) return self.db.zincrby(REDIS_KEY, -1, proxy.string()) # otherwise delete proxy else: logger.info(f'{proxy.string()} current score {score}, remove') return self.db.zrem(REDIS_KEY, proxy.string())
defmax(self, proxy: Proxy) -> int: """ set proxy to max score :param proxy: proxy :return: new score """ logger.info(f'{proxy.string()} is valid, set to {PROXY_SCORE_MAX}') if IS_REDIS_VERSION_2: return self.db.zadd(REDIS_KEY, PROXY_SCORE_MAX, proxy.string()) return self.db.zadd(REDIS_KEY, {proxy.string(): PROXY_SCORE_MAX})
defcount(self) -> int: """ get count of proxies :return: count, int """ return self.db.zcard(REDIS_KEY)
defall(self) -> List[Proxy]: """ get all proxies :return: list of proxies """ return convert_proxy_or_proxies(self.db.zrangebyscore(REDIS_KEY, PROXY_SCORE_MIN, PROXY_SCORE_MAX))
defbatch(self, start, end) -> List[Proxy]: """ get batch of proxies :param start: start index :param end: end index :return: list of proxies """ return convert_proxy_or_proxies(self.db.zrevrange(REDIS_KEY, start, end - 1))
if __name__ == '__main__': conn = RedisClient() result = conn.random() print(result)
from retrying import retry import requests from loguru import logger
classBaseCrawler(object): urls = []
@retry(stop_max_attempt_number=3, retry_on_result=lambda x: x is None) deffetch(self, url, **kwargs): try: response = requests.get(url, **kwargs) if response.status_code == 200: return response.text except requests.ConnectionError: return
@logger.catch defcrawl(self): """ crawl main method """ for url in self.urls: logger.info(f'fetching {url}') html = self.fetch(url) for proxy in self.parse(html): logger.info(f'fetched proxy {proxy.string()} from {url}') yield proxy
import pkgutil from .base import BaseCrawler import inspect
# load classes subclass of BaseCrawler classes = [] for loader, name, is_pkg in pkgutil.walk_packages(__path__): module = loader.find_module(name).load_module(name) for name, value in inspect.getmembers(module): globals()[name] = value if inspect.isclass(value) and issubclass(value, BaseCrawler) and value isnot BaseCrawler: classes.append(value) __all__ = __ALL__ = classes
asyncdeftest(self, proxy: Proxy): """ test single proxy :param proxy: Proxy object :return: """ asyncwith aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session: try: logger.debug(f'testing {proxy.string()}') asyncwith session.get(TEST_URL, proxy=f'http://{proxy.string()}', timeout=TEST_TIMEOUT, allow_redirects=False) as response: if response.status in TEST_VALID_STATUS: self.redis.max(proxy) logger.debug(f'proxy {proxy.string()} is valid, set max score') else: self.redis.decrease(proxy) logger.debug(f'proxy {proxy.string()} is invalid, decrease score') except EXCEPTIONS: self.redis.decrease(proxy) logger.debug(f'proxy {proxy.string()} is invalid, decrease score')
@logger.catch defrun(self): """ test main method :return: """ # event loop of aiohttp logger.info('stating tester...') count = self.redis.count() logger.debug(f'{count} proxies to test') for i in range(0, count, TEST_BATCH): # start end end offset start, end = i, min(i + TEST_BATCH, count) logger.debug(f'testing proxies from {start} to {end} indices') proxies = self.redis.batch(start, end) tasks = [self.test(proxy) for proxy in proxies] # run tasks using event loop self.loop.run_until_complete(asyncio.wait(tasks))
if __name__ == '__main__': tester = Tester() tester.run()
這里定義了一個(gè)類 Tester,__init__ 方法中建立了一個(gè) RedisClient 對(duì)象,供該對(duì)象中其他方法使用。接下來(lái),定義了一個(gè) test 方法,這個(gè)方法用來(lái)檢測(cè)單個(gè)代理的可用情況,其參數(shù)就是被檢測(cè)的代理。注意,test 方法前面加了 async 關(guān)鍵詞,這代表這個(gè)方法是異步的。方法內(nèi)部首先創(chuàng)建了 aiohttp 的 ClientSession 對(duì)象,可以直接調(diào)用該對(duì)象的 get 方法來(lái)訪問(wèn)頁(yè)面。
測(cè)試鏈接在這里定義為常量 TEST_URL。如果針對(duì)某個(gè)網(wǎng)站有抓取需求,建議將 TEST_URL 設(shè)置為目標(biāo)網(wǎng)站的地址,因?yàn)樵谧ト∵^(guò)程中,代理本身可能是可用的,但是該代理的 IP 已經(jīng)被目標(biāo)網(wǎng)站封掉了。例如,某些代理可以正常訪問(wèn)百度等頁(yè)面,但是對(duì)知乎來(lái)說(shuō)可能就被封了,所以我們可以將 TEST_URL 設(shè)置為知乎的某個(gè)頁(yè)面的鏈接。當(dāng)請(qǐng)求失敗、代理被封時(shí),分?jǐn)?shù)自然會(huì)減下來(lái),失效的代理就不會(huì)被取到了。
如果想做一個(gè)通用的代理池,則不需要專門設(shè)置 TEST_URL,既可以將其設(shè)置為一個(gè)不會(huì)封 IP 的網(wǎng)站,也可以設(shè)置為百度這類響應(yīng)穩(wěn)定的網(wǎng)站。
defrun_server(self): """ run server for api """ ifnot ENABLE_SERVER: logger.info('server not enabled, exit') return app.run(host=API_HOST, port=API_PORT, threaded=API_THREADED)
defrun(self): global tester_process, getter_process, server_process try: logger.info('starting proxypool...') if ENABLE_TESTER: tester_process = multiprocessing.Process(target=self.run_tester) logger.info(f'starting tester, pid {tester_process.pid}...') tester_process.start()
if ENABLE_GETTER: getter_process = multiprocessing.Process(target=self.run_getter) logger.info(f'starting getter, pid{getter_process.pid}...') getter_process.start()
if ENABLE_SERVER: server_process = multiprocessing.Process(target=self.run_server) logger.info(f'starting server, pid{server_process.pid}...') server_process.start()
tester_process.join() getter_process.join() server_process.join() except KeyboardInterrupt: logger.info('received keyboard interrupt signal') tester_process.terminate() getter_process.terminate() server_process.terminate() finally: # must call join method before calling is_alive tester_process.join() getter_process.join() server_process.join() logger.info(f'tester is {"alive"if tester_process.is_alive() else"dead"}') logger.info(f'getter is {"alive"if getter_process.is_alive() else"dead"}') logger.info(f'server is {"alive"if server_process.is_alive() else"dead"}') logger.info('proxy terminated')
if __name__ == '__main__': scheduler = Scheduler() scheduler.run()
當(dāng)前做目標(biāo)檢測(cè)的算法主要有兩種方法,有一階段式和兩階段式,英文叫做 One stage 和 Two stage,簡(jiǎn)述如下:
Two Stage:算法首先生成一系列目標(biāo)所在位置的候選框,然后再對(duì)這些框選出來(lái)的結(jié)果進(jìn)行樣本分類,即先找出來(lái)在哪,然后再分出來(lái)是啥,俗話說(shuō)叫「看兩眼」,這種算法有 R-CNN、Fast R-CNN、Faster R-CNN 等,這些算法架構(gòu)相對(duì)復(fù)雜,但準(zhǔn)確率上有優(yōu)勢(shì)。
One Stage:不需要產(chǎn)生候選框,直接將目標(biāo)定位和分類的問(wèn)題轉(zhuǎn)化為回歸問(wèn)題,俗話說(shuō)叫「看一眼」,這種算法有 YOLO、SSD,這些算法雖然準(zhǔn)確率上不及 Two stage,但架構(gòu)相對(duì)簡(jiǎn)單,檢測(cè)速度更快。
所以這次我們選用 One Stage 的有代表性的目標(biāo)檢測(cè)算法 YOLO 來(lái)實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼缺口的識(shí)別。
YOLO,英文全稱叫做 You Only Look Once,取了它們的首字母就構(gòu)成了算法名,
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import WebDriverException import time from loguru import logger
COUNT = 1000
for i in range(1, COUNT + 1): try: browser = webdriver.Chrome() wait = WebDriverWait(browser, 10) browser.get('https://captcha1.scrape.center/') button = wait.until(EC.element_to_be_clickable( (By.CSS_SELECTOR, '.el-button'))) button.click() captcha = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, '.geetest_slicebg.geetest_absolute'))) time.sleep(5) captcha.screenshot(f'data/captcha/images/captcha_{i}.png') except WebDriverException as e: logger.error(f'webdriver error occurred {e.msg}') finally: browser.close()
當(dāng)前模型的預(yù)測(cè)過(guò)程是通過(guò)命令行執(zhí)行的,但在實(shí)際使用的時(shí)候可能并不太方便,可以考慮將預(yù)測(cè)過(guò)程對(duì)接 API 服務(wù)器暴露出來(lái),比如對(duì)接 Flask、Django、FastAPI 等把預(yù)測(cè)過(guò)程實(shí)現(xiàn)為一個(gè)支持 POST 請(qǐng)求的接口,接口可以接收一張驗(yàn)證碼圖片,返回驗(yàn)證碼的文本信息,這樣會(huì)使得模型更加方便易用。
我們?cè)谧雠老x(chóng)的過(guò)程中經(jīng)常會(huì)遇到這樣的情況,最初爬蟲(chóng)正常運(yùn)行,正常抓取數(shù)據(jù),一切看起來(lái)都是那么美好,然而一杯茶的功夫可能就會(huì)出現(xiàn)錯(cuò)誤,比如 403 Forbidden,這時(shí)打開(kāi)網(wǎng)頁(yè)一看,可能會(huì)看到 “您的 IP 訪問(wèn)頻率太高” 這樣的提示。出現(xiàn)這種現(xiàn)象的原因是網(wǎng)站采取了一些反爬蟲(chóng)措施。比如,服務(wù)器會(huì)檢測(cè)某個(gè) IP 在單位時(shí)間內(nèi)的請(qǐng)求次數(shù),如果超過(guò)了這個(gè)閾值,就會(huì)直接拒絕服務(wù),返回一些錯(cuò)誤信息,這種情況可以稱為封 IP。
既然服務(wù)器檢測(cè)的是某個(gè) IP 單位時(shí)間的請(qǐng)求次數(shù),那么借助某種方式來(lái)偽裝我們的 IP,讓服務(wù)器識(shí)別不出是由我們本機(jī)發(fā)起的請(qǐng)求,不就可以成功防止封 IP 了嗎?
一種有效的方式就是使用代理,后面會(huì)詳細(xì)說(shuō)明代理的用法。在這之前,需要先了解下代理的基本原理,它是怎樣實(shí)現(xiàn)偽裝 IP 的呢?
1. 基本原理
代理實(shí)際上指的就是代理服務(wù)器,英文叫作 Proxy Server,它的功能是代理網(wǎng)絡(luò)用戶去取得網(wǎng)絡(luò)信息。形象地說(shuō),它是網(wǎng)絡(luò)信息的中轉(zhuǎn)站。在我們正常請(qǐng)求一個(gè)網(wǎng)站時(shí),是發(fā)送了請(qǐng)求給 Web 服務(wù)器,Web 服務(wù)器把響應(yīng)傳回給我們。如果設(shè)置了代理服務(wù)器,實(shí)際上就是在本機(jī)和服務(wù)器之間搭建了一個(gè)橋,此時(shí)本機(jī)不是直接向 Web 服務(wù)器發(fā)起請(qǐng)求,而是向代理服務(wù)器發(fā)出請(qǐng)求,請(qǐng)求會(huì)發(fā)送給代理服務(wù)器,然后由代理服務(wù)器再發(fā)送給 Web 服務(wù)器,接著由代理服務(wù)器再把 Web 服務(wù)器返回的響應(yīng)轉(zhuǎn)發(fā)給本機(jī)。這樣我們同樣可以正常訪問(wèn)網(wǎng)頁(yè),但這個(gè)過(guò)程中 Web 服務(wù)器識(shí)別出的真實(shí) IP 就不再是我們本機(jī)的 IP 了,就成功實(shí)現(xiàn)了 IP 偽裝,這就是代理的基本原理。
2. 代理的作用
那么,代理有什么作用呢?我們可以簡(jiǎn)單列舉如下。
突破自身 IP 訪問(wèn)限制,訪問(wèn)一些平時(shí)不能訪問(wèn)的站點(diǎn)。
隱藏真實(shí) IP。上網(wǎng)者也可以通過(guò)這種方法隱藏自己的 IP,免受攻擊。對(duì)于爬蟲(chóng)來(lái)說(shuō),我們用代理就是為了隱藏自身的 IP,防止自身的 IP 被封鎖。
3. 爬蟲(chóng)代理
對(duì)于爬蟲(chóng)來(lái)說(shuō),由于爬蟲(chóng)爬取速度過(guò)快,在爬取過(guò)程中可能遇到同一個(gè) IP 訪問(wèn)過(guò)于頻繁的問(wèn)題,此時(shí)網(wǎng)站就會(huì)讓我們輸入驗(yàn)證碼登錄或者直接封鎖 IP,這樣會(huì)給爬取帶來(lái)極大的不便。
注:公司的郵件系統(tǒng)一般會(huì)有會(huì)議什么的安排,比如我公司就用的 Outlook 和 Teams,但是它就比較難和我個(gè)人的待做清單(滴答清單)有機(jī)地融合在一起,所以,我干脆直接全部以自己的待做清單為準(zhǔn),我會(huì)在自己的待做清單里面再把今天我要做的所有事情都梳理一遍。